﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
using Ensynch;
using Ensynch.Collections.Generic;

namespace FIMQueryTool
{
    public class RecentList
    {
        // Create a logger for use in this class.
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(
                System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private int capacity;
        private string regPath;
        private string regKey;

        // XmlSerializer ignores private members.
        private List<string> sortedKeys = new List<string>();
        public List<string> SortedKeys
        {
            get
            {
                return sortedKeys;
            }
            set
            {
                sortedKeys = value;
            }
        }
        private SerializableDictionary<string, string> dictionary = new SerializableDictionary<string, string>();
        public SerializableDictionary<string, string> Dictionary
        {
            get
            {
                return dictionary;
            }
            set
            {
                dictionary = value;
            }
        }

        public event EventHandler ListChanged;

        public string this[string key]
        {
            get
            {
                for (int i = this.Count - 1; i >= 0; i--)
                {
                    if (sortedKeys[i].ToLower() == key.ToLower())
                    {
                        return dictionary[sortedKeys[i]];
                    }
                }
                return null;
            }
        }

        public KeyValuePair<string, string> this[int i]
        {
            get
            {
                return new KeyValuePair<string, string>(sortedKeys[i], dictionary[sortedKeys[i]]);
            }
        }

        public static RecentList TryGetFromRegistry(string regPath, string regKey, int capacity)
        {
            RecentList result = null;
            result = deserializeFromRegistry(regPath, regKey);
            if (result != null)
            {
                result.capacity = capacity;
            }
            else
            {
                result = new RecentList(regPath, regKey, capacity);
            }
            return result;
        }

        /// <summary>
        /// Do not use this constructor.
        /// </summary>
        private RecentList() { }

        private RecentList(string regPath, string regKey, int capacity)
            : base()
        {
            this.regPath = regPath;
            this.regKey = regKey;
            this.capacity = capacity;
        }

        private static RecentList deserializeFromRegistry(string regPath, string regKey)
        {
            RecentList result = null;
            try
            {
                object compressed = EnsynchTools.GetRegValue(regPath, regKey);
                if (compressed != null)
                {
                    string uncompressed = EnsynchTools.Uncompress(compressed.ToString());
                    using (StringReader stringReader = new StringReader(uncompressed))
                    using (XmlTextReader xmlTextReader = new XmlTextReader(stringReader))
                    {
                        XmlSerializer xmlSerializer;
                        xmlSerializer =
                            new XmlSerializer(typeof(RecentList));
                        result = (RecentList)xmlSerializer.Deserialize(xmlTextReader);
                        result.regPath = regPath;
                        result.regKey = regKey;
                        log.Debug("[deserializeFromRegistry]\r\n" + result.ToXml());
                    }
                }
            }
            catch (Exception exc)
            {
                log.Error("[deserializeFromRegistry]", exc);
            }
            return result;
        }

        private void serializeToRegistry()
        {
            string uncompressed = this.ToXml();
            log.Debug("[serializeToRegistry]\r\n" + uncompressed);
            string compressed = EnsynchTools.Compress(uncompressed);
            EnsynchTools.SetRegValue(regPath, regKey, compressed);
        }

        public string ToXml()
        {
            //XmlSerializer xmlSerializer = new XmlSerializer(typeof(SerializableDictionary<string, string>));
            //StringWriter stringWriter = new StringWriter();
            //xmlSerializer.Serialize(stringWriter, this.dictionary);
            //string serializedXML = stringWriter.ToString();
            //return serializedXML;

            XmlSerializer xmlSerializer = new XmlSerializer(typeof(RecentList));
            StringWriter stringWriter = new StringWriter();
            xmlSerializer.Serialize(stringWriter, this);
            string serializedXML = stringWriter.ToString();
            return serializedXML;
        }

        public void Push(string key, string value)
        {
            this.remove(key);
            this.add(key, value);
            int count = dictionary.Count;
            int j = -1;
            for (int i = count; i > capacity; i--)
            {
                this.remove(sortedKeys[i]);
                sortedKeys.RemoveAt(i);
                //this.RemoveAt(i);
            }
            listChanged();
        }

        private void remove(string key)
        {
            for (int i = dictionary.Count - 1; i >= 0; i--)
            {
                if (sortedKeys[i].ToLower() == key.ToLower())
                {
                    dictionary.Remove(sortedKeys[i]);
                    sortedKeys.RemoveAt(i);
                }
                //if (this[i].Key.ToLower() == key.ToLower())
                //{
                //    this.RemoveAt(i);
                //}
            }
        }

        private void add(string key, string value)
        {
            dictionary.Add(key, value);
            sortedKeys.Add(key);
            //base.Add(new KeyValuePair<string, string>(key, value));
        }

        private void listChanged()
        {
            serializeToRegistry();
            if (ListChanged != null)
            {
                this.ListChanged(this, new EventArgs());
            }
        }

        public int Count
        {
            get
            {
                return sortedKeys.Count;
            }
        }

    }
}
